package com.lafabrick.components
{
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import mx.containers.HBox;
	import mx.containers.TitleWindow;
	import mx.core.UIComponent;
	import mx.core.mx_internal;
	
	use namespace mx_internal;
	
	[IconFile("DraggableWindowIcon.png")]
	
	/**
	 * Evénement déclenché lorsque l'utilisateur drag le composant
	 */
	[Event(name="startDragging", type="mx.events.Event")]
	
	/**
	 * Evénement déclenché lorsque l'utilisateur stop le drag
	 */
	[Event(name="stopDragging", type="mx.events.Event")]
	
	/**
	 * Evénement déclenché lorsque l'utilisateur déplace le composant
	 */
	[Event(name="isDragging", type="mx.events.Event")]
	
	/**
	 * Composant étendu de TitleWindow. 
	 * Ajout des fonctionnalitées Drag.
	 */
	public class DraggableWindow extends TitleWindow
	{
		private var _horizontalChildAlign:String = "right";
		
		[Inspectable(enumeration="left,center,right", verbose=1, category="Draggable Properties")]
		public function set horizontalChildAlign(value:String):void
		{
            this._horizontalChildAlign = value;         
        }
        
        public function get horizontalChildAlign() : String
        {
        	return this._horizontalChildAlign;
        }
        
        private var _verticalChildAlign:String = "middle";
		
		[Inspectable(enumeration="top,middle,bottom", verbose=1, category="Draggable Properties")]
		public function set verticalChildAlign(value:String):void
		{
            this._verticalChildAlign = value;         
        }
        
        public function get verticalChildAlign() : String
        {
        	return this._verticalChildAlign;
        }
		
		[ArrayElementType("mx.core.UIComponent")]
		public var titleBarChildren:Array = [];
		
		protected var hBox:HBox;
		
		/**
		 * @private
		 */
		protected var _dragEnabled:Boolean = false;
		
		protected var _buttonMarginRight:Number = 10;
		protected var _buttonMarginTop:Number = 10;
		
		/**
		 * @private
		 */
		protected var _buttonSpacing : Number = 5;
		
		/**
		 * Constructeur
		 */
		public function DraggableWindow() 
		{
			super();
		}
		
		[Inspectable(defaultValue=10, verbose=1, category="Expanded Properties")]
		public function set buttonSpacing(value:Number) : void {
			_buttonSpacing = value;
		}
		/**
		 * Définit l'espacement entre les boutons de la titleBar.
		 * @param value:Number (défaut : 10)
		 */
		public function get buttonSpacing() : Number 
		{
			return this._buttonSpacing;
		}
		
		private function topIndex(e:MouseEvent) : void 
		{
			parent.setChildIndex(this, parent.numChildren - 1);
		}
		
		[Inspectable(defaultValue=false, verbose=1, category="Expanded Properties")]
        public function set dragEnabled(value:Boolean):void
        {
            this._dragEnabled = value;
        }
        /**
		 * Définit si le composant est draggable (true) ou non
		 * @param value:Boolean true / false
		 */
        public function get dragEnabled():Boolean{
            return this._dragEnabled;
        }
        
		[Inspectable(defaultValue=10, verbose=1, category="Expanded Properties")]
        public function set buttonMarginRight(value:Number):void
        {
            this._buttonMarginRight = value;
        }
        /**
		 * Définit la marge RIGHT des boutons de la bar de titre  (default = 10). <br/>Une marge RIGHT négative vous permet de décaller les boutons de la titleBar vers l'extérieur droit de la fenêtre.
		 * @param value:Number
		 */
        public function get buttonMarginRight():Number
        {
            return this._buttonMarginRight;
        }
        
		[Inspectable(defaultValue=10, verbose=1, category="Expanded Properties")]
        public function set buttonMarginTop(value:Number):void
        {
            this._buttonMarginTop = value;
        }
         /**
		 * Définit la marge TOP des boutons de la bar de titre (default = 10). <br/>Une marge TOP négative vous permet de décaller les boutons de la titleBar vers l'extérieur haut de la fenêtre.
		 * @param value:Number
		 */
        public function get buttonMarginTop():Number
        {
            return this._buttonMarginTop;
        }
        
        /**
		 * @private
		 */
		override protected function createChildren():void 
		{
			
			super.createChildren();
			
			
			closeButton.explicitWidth = getStyle("closeButtonUpSkin").width;
			closeButton.explicitHeight = getStyle("closeButtonUpSkin").height;
            
            this.layout = "absolute";
            
			this.titleBar.addEventListener(MouseEvent.MOUSE_DOWN, topIndex);
			
			
			hBox = new HBox();
			hBox.includeInLayout = true;
			hBox.setStyle("horizontalAlign", this._horizontalChildAlign);
			hBox.setStyle("verticalAlign", this._verticalChildAlign);
			hBox.x = title != "" ? titleTextField.x+titleTextField.width : 0;
			
			hBox.width = title != "" ? titleBar.width-hBox.x : titleBar.width;
			hBox.height = 5;
			hBox.horizontalScrollPolicy = "off";
			hBox.verticalScrollPolicy = "off";
			hBox.name = "__hBox__";

			var i:Number = 0;

			for each (var child:UIComponent in titleBarChildren) {
				if (hBox.getChildByName(child.name))
					hBox.removeChildAt(i);
				
				child.focusEnabled = false;
				hBox.addChildAt(child, i);
				i++;

			}
			
			titleBarChildren = [];
			
			var index:Number = this.titleBar.getChildIndex(DisplayObject(this.titleTextField)) + 1;
			
			this.titleBar.addChildAt(hBox, index);
				

		}


        /**
        * @private
        */
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			closeButton.move(titleBar.width - (closeButton.width) - buttonMarginRight, buttonMarginTop);
			
			var childArray:Array = hBox.getChildren();
				
			for (var i:Number = 0; i < childArray.length;i++) {
				
				childArray[i].setActualSize(
            		childArray[i].getExplicitOrMeasuredWidth(),
            		childArray[i].getExplicitOrMeasuredHeight());
            	
            	childArray[i].move(childArray[i].x, childArray[i].y);
            		
			
			}
			
			
			var px:Number = title != "" ? this.titleTextField.x+this.titleTextField.getExplicitOrMeasuredWidth() : 0;
			var wi:Number;
			if(showCloseButton) {
				wi = title != "" ? titleBar.width-closeButton.width-px-2*_buttonSpacing : titleBar.width-closeButton.width-3*_buttonSpacing;
			}
			else {
				wi = title != "" ? titleBar.width-px-2*_buttonSpacing : titleBar.width-2*_buttonSpacing;
			}
			
			
			hBox.move(px+this._buttonSpacing, this._buttonMarginTop);
			
			hBox.setActualSize(wi, titleBar.height-this._buttonMarginTop);
		}
		
		
		// ------------------
		// DRAG 
		/**
		 * @private
		 */
		protected var _isDrag:Boolean = false;
		
		private var _startX: Number;
        private var _startY: Number;
        private var _dragStartX: Number;
        private var _dragStartY: Number;
		
		private function onMouseDown( e:MouseEvent ) : void
		{
			var p: Point = globalToLocal(new Point(e.stageX, e.stageY));
           
          
            if (p.y < getHeaderHeight() - 10) {
				_startX = this.x;
	            _startY = this.y;
	            _dragStartX = e.stageX;
	            _dragStartY = e.stageY;
				
				_isDrag = true;
				dispatchEvent(new Event("startDragging"));
            }
		}
		
		private function onMouseUp( e:MouseEvent ) : void
		{
			_isDrag = false;
			this.dispatchEvent(new Event("stopDragging"));
		}
		
		private function onMouseMove( e:MouseEvent ) : void
		{
			if (_isDrag) {
				this.move(_startX + e.stageX - _dragStartX, _startY + e.stageY - _dragStartY);
				this.dispatchEvent(new Event("isDragging"));
			}
		}
		
		/**
		 * @private
		 */
		override public function initialize(): void {
            super.initialize();
            if (_dragEnabled) {
            	this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
	            systemManager.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
	            systemManager.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            }
            else {
            	this.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
	            systemManager.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
	            systemManager.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            }
        }
	}
}